#pragma once

#include <d3d9.h>
#include <d3dx9.h>
#include <cmath>
#include <string>
#include "PD3DFrustum.h"
#include "PD3DFileX.h"

#define RELEASE(obj) if ((obj) != NULL) { (obj)->Release();	(obj) = NULL;}
// <67E7BBF0-AD9C-4216-8721-F9C427ACBAE3>
DEFINE_GUID(GUID_MAPVERTEX, 0x67e7bbf0, 0xad9c, 0x4216, 0x87, 0x21, 0xf9, 0xc4, 0x27, 0xac, 0xba, 0xe3);
// <84320DCA-9D76-4C51-A13E-A38BF3033C67>
DEFINE_GUID(GUID_TILE, 0x84320dca, 0x9d76, 0x4c51, 0xa1, 0x3e, 0xa3, 0x8b, 0xf3, 0x3, 0x3c, 0x67);
// <E327EE29-B8EF-4831-A4B3-C87C0A13726A>
DEFINE_GUID(GUID_MAP_INFO, 0xe327ee29, 0xb8ef, 0x4831, 0xa4, 0xb3, 0xc8, 0x7c, 0xa, 0x13, 0x72, 0x6a);

char *templates = "xof 0302txt 0032\
template MAP_INFO {\
   <E327EE29-B8EF-4831-A4B3-C87C0A13726A>\
   DWORD N_TILES;\
   DWORD N_SURFACES;\
   DWORD N_LIGHTS;\
   DWORD N_VERTEX;\
   }\
template MAPVERTEX{\
  <67E7BBF0-AD9C-4216-8721-F9C427ACBAE3>\
		FLOAT x, y, z;\
		FLOAT nx, ny, nz;\
		FLOAT u0, v0;\
		FLOAT u1, v1;\
}\
template TILE{\
    <84320DCA-9D76-4C51-A13E-A38BF3033C67>\
       DWORD firstVertexIndex;\
       DWORD numFaces;\
	   DWORD textureIndex;\
	   FLOAT angle;\
	   FLOAT height;\
}";
using namespace std;

namespace pd3d {

	struct MAPVERTEX
	{
		float x, y, z;
		float nx, ny, nz;
		float u0, v0;
		float u1, v1;
	};

	const DWORD MAPVERTEX_FVF = (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX2);

	struct TILE
	{
		TILE()
		{
			firstVertexIndex = numFaces = textureIndex = 0;
			angle = 0.0f;
			height = 0;
		}

		int firstVertexIndex;
		int numFaces;
		int textureIndex;
		float angle;
		float height;
	};

	struct SURFACE
	{
		SURFACE()
		{
			tile = lightmap = NULL;
		}

		~SURFACE()
		{
			RELEASE(tile);
			RELEASE(lightmap);
		}
		LPDIRECT3DTEXTURE9 tile;
		LPDIRECT3DTEXTURE9 lightmap;	
	};

	struct RENDERDATA
	{
		DWORD FVF;
		int vertexSize;
		LPDIRECT3DVERTEXBUFFER9 vertexBuffer;
		int skipValue;
	};

	struct LIGHT
	{
		LIGHT()
		{
			lightRange = r = g = b = 0.0f;
			templateIndex = 0;
		}
		float lightRange, r, g, b;
		int templateIndex;
	};
	struct MAP_INFO 
	{
		DWORD N_TILES;
		DWORD N_SURFACES;
		DWORD N_LIGHTS;
		DWORD N_VERTEX;
	};
	class PD3DTileMapEngine
	{
	private:
		static const int N_SURFACES = 6;
		static const int N_LIGHTS = 3;
		SURFACE surfaces[N_SURFACES];
		D3DLIGHT9 lights[N_LIGHTS];
		SURFACE lightSurfaces[N_LIGHTS];
		RENDERDATA renderData;
		LPDIRECT3DDEVICE9 device;
		LPDIRECT3DVERTEXBUFFER9 vertexBuffer;
		D3DXVECTOR3 scale;
		FrustumCulling frustum;
		int nRenderedTitles;
		int nRenderedLights;
		TILE *tiles;
		MAP_INFO *info;
		MAPVERTEX *triangles;
		void initTiles(void);
	public:
		PD3DFileX *file;
		PD3DTileMapEngine(LPDIRECT3DDEVICE9 device, const D3DXVECTOR3 &scale = D3DXVECTOR3(1.0f, 1.0f, 1.0f));
		~PD3DTileMapEngine(void);
		void render(const int *tileMap, int theMapSize, bool frustumCulling = true, const int *lightMap = NULL, bool lightFrustumCulling = true);
		int getNRenderedTiles(void);
		int getNRenderedLights(void);
	};
}
